package com.alameda.listener;

import com.alameda.common.base.constant.LoginConstant;
import com.alameda.common.base.constant.ProjectConstant;
import com.alameda.common.base.enums.EventMessageTypeEnum;
import com.alameda.common.base.enums.UserTypeEnum;
import com.alameda.common.commonpent.event.message.EventMessage;
import com.alameda.common.utils.*;
import com.alameda.pojo.user.AdUserDO;
import com.alameda.service.user.AdUserOperateLogService;
import com.alameda.service.user.AdUserService;
import com.alameda.user.api.ApUserProvider;
import com.alameda.user.dto.AdUserDTO;
import com.alameda.user.dto.AdUserOperateLogDTO;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;

import static com.alameda.common.base.constant.LoginConstant.TOKEN;
import static com.alameda.common.base.constant.MediaConstant.StringConstant.EMPTY_STRING;
import static com.alameda.common.base.constant.ProjectConstant.EVENT_MESSAGE_TYPE;

/**
 * 管理端服务事件监听器
 *
 * @author Lv
 * @date 2025/1/4
 */
@Slf4j
@Component
public class AdminEventListener {

    @Autowired
    private AdUserOperateLogService adUserOperateLogService;

    /**
     * 监听事件
     *
     * @param eventMessage 事件消息
     */
    @SuppressWarnings("all")
    @EventListener
    public void onEvent(EventMessage eventMessage) {
        String message = eventMessage.getMessage();
        Map<String, Object> map = JSONObject.parseObject(message, Map.class);
        // 获取消息类型
        String messageTypeCode = (String) map.get(EVENT_MESSAGE_TYPE);
        Boolean aBoolean = EventMessageTypeEnum.OPERATE.getTypeCode().equals(messageTypeCode)
                ? dealMessageOperateLogSave(map)
                : dealTokenRenewal(map);
    }

    @DubboReference
    private ApUserProvider apUserProvider;

    /**
     * 处理token续期
     *
     * @param map 事件消息
     */
    private Boolean dealTokenRenewal(Map<String, Object> map) {
        String token = (String) map.get(TOKEN);
        Map<String, Object> tokenInfoMap = JwtUtils.parseToken(token);

        return UserTypeEnum.APP.getTypeCode().equals(tokenInfoMap.get(LoginConstant.USER_TYPE))
                // 处理移动端token续期
                ? apUserProvider.dealApUserTokenRenewal(token)
                // 处理管理端token续期
                : adUserService.dealAdUserTokenRenewal(token);
    }

    /**
     * 处理操作日志保存
     *
     * @param map 事件消息
     */
    private Boolean dealMessageOperateLogSave(Map<String, Object> map) {
        // 获取账号
        String userName = PubUtils.isNull(ThreadLocalUtils.getParseResult()) || PubUtils.isEmpty(ThreadLocalUtils.getUserName())
                ? getUserName(map)
                : ThreadLocalUtils.getUserName();

        // 获取用户类型
        String userType = PubUtils.isNull(ThreadLocalUtils.getParseResult()) || PubUtils.isEmpty(ThreadLocalUtils.getUserType())
                ? getUserType(userName)
                : ThreadLocalUtils.getUserType();

        AdUserOperateLogDTO adUserOperateLogDTO = new AdUserOperateLogDTO();
        adUserOperateLogDTO.setUserName(userName);
        adUserOperateLogDTO.setUserType(Integer.valueOf(userType));
        adUserOperateLogDTO.setOperateApiName((String) map.get(ProjectConstant.OperateInfoPropertyConstant.API_NAME));
        adUserOperateLogDTO.setOperateApiTime(LocalDateTime.now());
        adUserOperateLogDTO.setOperateApiResult((String) map.get(ProjectConstant.OperateInfoPropertyConstant.OPERATE_RESULT));
        adUserOperateLogDTO.setOperateApiTraceId((String) map.get(ProjectConstant.OperateInfoPropertyConstant.TRACE_ID));

        // 异步保存日志
        ThreadPoolUtils.execute(() -> adUserOperateLogService.saveOperateLogInfo(adUserOperateLogDTO));
        return Boolean.TRUE;
    }

    @Autowired
    private AdUserService adUserService;

    /**
     * 获取用户类型
     *
     * @param userName 账号
     * @return
     */
    private String getUserType(String userName) {
        AdUserDO adUserDO = adUserService.findByUserName(userName);
        if (PubUtils.isNull(adUserDO)) {
            return EMPTY_STRING;
        }
        Map<String, String> extDataMap = adUserDO.getExtData();
        return extDataMap.get(UserTypeEnum.getKeyString());
    }

    /**
     * 获取用户账号
     *
     * @param map 事件消息内容
     * @return
     */
    private String getUserName(Map<String, Object> map) {
        Object requestParam = map.get(ProjectConstant.OperateInfoPropertyConstant.REQUEST_PARAM);
        AdUserDTO adUserDTO = ObjectUtils.convert(requestParam, AdUserDTO.class);
        return Optional.ofNullable(adUserDTO).orElse(AdUserDTO.builder().build()).getUsername();
    }
}
